extends ItemContainer


class_name MoveComponent
"""
移动组件(只负责处理当前方向和当前速度)
"""


## 移动/静止状态变更通知
signal event_moving_state_changed(node: MoveComponent, is_moving: bool)


## 当前移动速度
@export var speed: float = 0:
    set(v):
        # 限制速度必须大于等于0
        speed = max(v, 0)
## 当前移动方向
@export var direction: Vector2 = Vector2.ZERO
## 是否在子节点从树中退出时自动drop
@export var is_drop_when_exiting: bool = true
## 代理的移动对象
@export var wrapper: Node2D = null:
    set(v):
        wrapper = v
        character = wrapper as CharacterBody2D if wrapper else null


# 引用的CharacterBody2D对象
var character: CharacterBody2D = null


var __is_last_moving: bool = false
var __tree_exiting_map: Dictionary[Node, Callable] = {}


func __check_exports() -> Dictionary:
    return IComponent.merge({
        "speed": func(): return speed >= 0,
        "wrapper": [IComponent.find_up_nearby.bind(self, func(x): return x is Node2D, wrapper)],
        "items": [IComponent.find_children.bind(self, func(x): return x is MoveElement, items)],
    }, super.__check_exports())

func __prepare() -> void:
    super.__prepare()

    for e in items:
        e.on_move_ready()

func __on_tree_exiting(cmpt: Node) -> void:
    remove(cmpt)
    var cb: Callable = __tree_exiting_map.get(cmpt)
    if cb:
        cmpt.tree_exiting.disconnect(cb)

func append(cmpt: Node) -> void:
    if is_drop_when_exiting:
        var cb: Callable = __on_tree_exiting.bind(cmpt)
        __tree_exiting_map[cmpt] = cb
        cmpt.tree_exiting.connect(cb)
    cmpt.on_move_ready()
    super.append(cmpt)

# 返回代理对象是否是CharacterBody2D
func is_character() -> bool:
    return character and character is CharacterBody2D

# 返回代理对象是否为空
func is_null() -> bool:
    return wrapper == null

# 返回是否处于移动中的状态
func is_moving() -> bool:
    return not is_stop()

# 返回是否处于停止状态
func is_stop() -> bool:
    return direction.is_zero_approx()

# 停止移动
func stop() -> void:
    direction = Vector2.ZERO

# 返回朝向鼠标的方向
func mouse_direction() -> Vector2:
    return (wrapper.get_global_mouse_position() - wrapper.global_position).normalized()

# 更改前进方向
func turn(forward_direction: Vector2) -> MoveComponent:
    direction = forward_direction
    # 修改并触发通知
    for e in items:
        if e and IComponent.is_available(e):
            e.on_move_direction_changed()
    return self

# 返回朝向目标的方向
func direction_to(target: Node2D) -> Vector2:
    var pos: Vector2 = target.global_position
    var body: Vector2 = wrapper.global_position
    return (pos - body).normalized()

# 返回与目标的距离(平方)
func distance_squared_to(target: Node2D) -> float:
    var pos: Vector2 = target.global_position
    var body: Vector2 = wrapper.global_position
    return body.distance_squared_to(pos)

# 返回与目标的距离
func distance_to(target: Node2D) -> float:
    var pos: Vector2 = target.global_position
    var body: Vector2 = wrapper.global_position
    return body.distance_to(pos)

# 获取当前移动速度
func get_velocity(delta) -> Vector2:
    var velocity: Vector2 = Vector2.ZERO
    for e in items:
        if e and IComponent.is_available(e):
            velocity += e.yield_move(delta)
    velocity += direction * speed
    return velocity

# 移动
func move_forward(velocity: Vector2, delta: float) -> void:
    if is_character():
        character.velocity = velocity
        character.move_and_slide()
    else:
        wrapper.position += (velocity * delta)

func move_process(delta: float) -> void:
    var v: Vector2 = get_velocity(delta)
    var is_current_moving: bool = not v.is_zero_approx()
    if is_current_moving != __is_last_moving:
        __is_last_moving = !__is_last_moving
        event_moving_state_changed.emit(self, is_current_moving)
    move_forward(v, delta)

func _physics_process(delta):
    move_process(delta)
